/*****************************************************
** Author: 
** Date: 2020-03-26
*
*****************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "dna_json.h"


#define tc_log(_fmt_, ...)          printf("[TC][%s:%d][%s] "_fmt_"\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__)
#define tc_log_err(_fmt_, ...)      printf("[TC][ERR][%s:%d][%s] "_fmt_"\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__)


struct snap_kv {
	unsigned short type;
	char key[16];
};

enum {
	SNAP_KV_TYPE_INT,
	SNAP_KV_TYPE_STRING,
};

/**
 * @brief
 * @param  None
 * @retval None
 */
static const char *snapshot_update_type_itoa(int type)
{
	const char *map[] = {"int", "string"};
	return map[type];
}

static void snapshot_update_dump_kv(struct snap_kv *kv, int num)
{
	int i;
	tc_log("kv num %d", num);
	for (i = 0; i < num; ++i)
		tc_log("[%s] %s", snapshot_update_type_itoa(kv[i].type), kv[i].key);
}

static int snapshot_update_get_kv(const char *input, struct snap_kv *kv, int kv_max_num)
{
	char *walk = input;
	char *pos[2];
	int i, keysize, cnt = 0;

	tc_log("input %s", input);

	while (1) {
		for (i = 0; i < 2; ++i) {
			pos[i] = strchr(walk, '"');
			tc_log("pos[%d] %p %s", i, pos[i], pos[i]);
			if (pos[i] == NULL)
				return cnt;

			walk = pos[i] + 1;
		}

		keysize = (unsigned int)pos[1] - (unsigned int)pos[0] - 1;
		tc_log("key length %d", keysize);

		memset(&kv[cnt], 0x0, sizeof(struct snap_kv));
		memcpy(kv[cnt].key, pos[0] + 1, keysize);

		// tc_log("%c", *(pos[1] + 2));
		switch (*(pos[1] + 2)) {
			case '"':
			kv[cnt].type = SNAP_KV_TYPE_STRING;
			/* skip value "" */
			walk = strchr(walk, ',');
			break;

			default:
			kv[cnt].type = SNAP_KV_TYPE_INT;
			break;
		}

		cnt++;

		if (cnt >= kv_max_num) {
			tc_log("kv is full");
			return cnt;
		}

		/* last keyvalue is string type */
		if (walk == NULL)
			return cnt;
	}
}

static int snapshot_update_do(char *snapshot, int snapbuffsize, struct snap_kv *snap, int snap_num, char *new)
{
	dna_json_object_t jobjnewsnap, jobjsnap, jobjnew;
	char newsnap[1024], typeflag;
	int i, val, newsnapsize;
	char str[32];

	dna_json_object_init(&jobjsnap, snapshot);
	dna_json_object_init(&jobjnew, new);

	dna_json_str_init(&jobjnewsnap, newsnap, sizeof(newsnap));
	dna_json_start_object(&jobjnewsnap);

	for (i = 0; i < snap_num; ++i) {
		typeflag = 0;
		/* get from new, if exist, then update snapshot */
		switch (snap[i].type) {
			case SNAP_KV_TYPE_INT:
			if (dna_json_get_val_int(&jobjnew, snap[i].key, &val) == 0) {
				tc_log("get '%s' %d from new", snap[i].key, val);
				typeflag |= (1 << SNAP_KV_TYPE_INT);
			}
			break;

			case SNAP_KV_TYPE_STRING:
			if (dna_json_get_val_str(&jobjnew, snap[i].key, str, sizeof(str)) == 0) {
				tc_log("get '%s' %s from new", snap[i].key, str);
				typeflag |= (1 << SNAP_KV_TYPE_STRING);
			}
			break;

			default:
			continue;
		}

		if (typeflag == 0) {
			/* get from snapshot */
			switch (snap[i].type) {
				case SNAP_KV_TYPE_INT:
				if (dna_json_get_val_int(&jobjsnap, snap[i].key, &val) == 0) {
					tc_log("get '%s' %d from snapshot", snap[i].key, val);
					typeflag |= (1 << SNAP_KV_TYPE_INT);
				}
				break;

				case SNAP_KV_TYPE_STRING:
				if (dna_json_get_val_str(&jobjsnap, snap[i].key, str, sizeof(str)) == 0) {
					tc_log("get '%s' %s from snapshot", snap[i].key, str);
					typeflag |= (1 << SNAP_KV_TYPE_STRING);
				}
				break;

				default:
				continue;
			}
		}
			
		switch (typeflag) {
			case (1 << SNAP_KV_TYPE_INT):
			if (dna_json_set_val_int(&jobjnewsnap, snap[i].key, val) == 0)
				tc_log("set '%s' %d to new snapshot success", snap[i].key, val);
			else
				tc_log_err("set '%s' %d to new snapshot failed", snap[i].key, val);
			break;

			case (1 << SNAP_KV_TYPE_STRING):
			if (dna_json_set_val_str(&jobjnewsnap, snap[i].key, str) == 0)
				tc_log("set '%s' %s to new snapshot success", snap[i].key, str);
			else
				tc_log_err("set '%s' %s to new snapshot failed", snap[i].key, str);
			break;
		}
	}

	dna_json_close_object(&jobjnewsnap);

	if ((newsnapsize = dna_json_str_len(&jobjnewsnap)) >= snapbuffsize) {
		tc_log_err("new snap size %d exceed %d", newsnapsize, snapbuffsize);
		return -1;
	}

	memset(snapshot, 0x0, snapbuffsize);
	memcpy(snapshot, newsnap, newsnapsize);
	return newsnapsize;
}

int snapshot_update(char *snapshot, int snapsize, int snapbuffsize, const char *new)
{
	struct snap_kv snap[8];
	int snap_keynum;

	if (snapshot == NULL || snapbuffsize <= 0)
		return -1;

	if (snapsize <= 0) {
		memset(snapshot, 0x0, snapbuffsize);
		memcpy(snapshot, new, strlen(new));
		return strlen(new);
	}
	
	snap_keynum = snapshot_update_get_kv(snapshot, snap, 8);
	snapshot_update_dump_kv(snap, snap_keynum);

	return snapshot_update_do(snapshot, snapbuffsize, snap, snap_keynum, new);
}

/* End of file */



